﻿using System;
using System.Linq;
using FluentValidation;
using LINQPad.OpenAccess.Metadata;
using Telerik.OpenAccess;
using Telerik.OpenAccess.Metadata;

namespace LINQPad.OpenAccess.UI.ViewModel.Validators
{
    /// <summary>
    /// Validator for <see cref="BasicSettingsViewModel" /> instances
    /// </summary>
    public class BasicSettingsViewModelValidator : AbstractValidator<BasicSettingsViewModel>
    {
        private Func<BasicSettingsViewModel, bool> IsEmpty( Func<BasicSettingsViewModel, string> propertySelector )
        {
            return e => String.IsNullOrWhiteSpace( propertySelector( e ) );
        }
        private bool ProvideAtLeastOneUsableConstructor( IContextTypeInfo contextTypeInfo )
        {
            return contextTypeInfo != null && ( contextTypeInfo.HasCustomConstructor || contextTypeInfo.HasDefaultConstructor );
        }
        private string GetCtorMissingErrorFormat( )
        {
            return String.Format
                            (
                                "The context type needs to provide at least one of the following constructors:\n - {{0}}()\n -{{0}}({0},{1},{2}"
                                , typeof( string ).Name
                                , typeof( BackendConfiguration ).Name
                                , typeof( MetadataSource ).Name
                            );

        }
        private Func<BasicSettingsViewModel, object>[] GetCtoMissingErrorFormatArgs( )
        {
            return new Func<BasicSettingsViewModel, object>[]
                    {
                        o => o.SelectedContextType == null ? null : o.SelectedContextType.Name
                    };

        }

        /// <summary>
        /// Initializes a new instance of the <see cref="BasicSettingsViewModelValidator" /> class.
        /// </summary>
        public BasicSettingsViewModelValidator( )
        {
            // assembly file path
            this.RuleFor( b => b.AssemblyFilePath )
                .NotEmpty( )
                .WithMessage( "no assembly file path set !" );
            this.RuleFor( b => b.AssemblyFilePathExists )
                .Equal( true )
                .Unless( IsEmpty( e => e.AssemblyFilePath ) )
                .WithMessage( "the assembly file path is invalid !" );

            // app config file path
            this.RuleFor( b => b.AppConfigFilePath )
                .NotEmpty( )
                .When( b => b.UseDefaultConstructor )
                .WithMessage( "an application config file is required for the default constructor !" );

            this.RuleFor( b => b.AppConfigFilePathExists )
                .Equal( true )
                .Unless( IsEmpty( e => e.AppConfigFilePath ) )
                .WithMessage( "the application config file path is invalid !" );


            // context type
            this.RuleFor( b => b.SelectedContextType )
                .NotNull( )
                .WithMessage( "no context type set !" );
            this.RuleFor( b => b.SelectedContextType )
                .Must( ProvideAtLeastOneUsableConstructor )
                .WithMessage( GetCtorMissingErrorFormat( ), GetCtoMissingErrorFormatArgs( ) )
                .When( p => p.SelectedContextType != null );

            // selected metadata source
            this.RuleFor( b => b.SelectedMetadataSource )
                .NotNull( )
                .Unless( b => b.UseDefaultMetadataSource || b.UseDefaultConstructor )
                .WithMessage( "no metadata source set !" );
        }
    }
}
